package cloud.daodao.storm.security.service;

import cloud.daodao.storm.common.security.model.rsa.*;
import cloud.daodao.storm.security.config.AppConfig;
import cloud.daodao.storm.common.security.error.SecurityError;
import cloud.daodao.storm.common.error.AppException;
import cloud.daodao.storm.common.util.security.RsaUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;

@Slf4j
@Service
public class RsaService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private AppConfig appConfig;

    public RsaCipherData rsaEncrypt(RsaCipherParam param) {
        String key = param.getKey();
        String source = param.getSource();
        String target;
        PublicKey publicKey;
        try {
            publicKey = RsaUtil.publicKey(key);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_PUBLIC_KEY_ERROR, e);
        }
        try {
            target = RsaUtil.encrypt(publicKey, source);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_ENCRYPT_ERROR, e);
        }
        RsaCipherData data = new RsaCipherData();
        data.setTarget(target);
        return data;
    }

    public RsaCipherData rsaDecrypt(RsaCipherParam param) {
        String key = param.getKey();
        String source = param.getSource();
        String target;
        PrivateKey privateKey;
        try {
            privateKey = RsaUtil.privateKey(key);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_PRIVATE_KEY_ERROR, e);
        }
        try {
            target = RsaUtil.decrypt(privateKey, source);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_DECRYPT_ERROR, e);
        }
        RsaCipherData data = new RsaCipherData();
        data.setTarget(target);
        return data;
    }

    public RsaSignData rsaSign(RsaSignParam param) {
        String key = param.getKey();
        String data = param.getData();
        PrivateKey privateKey;
        try {
            privateKey = RsaUtil.privateKey(key);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_PRIVATE_KEY_ERROR, e);
        }
        String sign;
        try {
            sign = RsaUtil.sign(privateKey, data);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_SIGN_ERROR, e);
        }
        RsaSignData d = new RsaSignData();
        d.setSign(sign);
        return d;
    }

    public RsaVerifyData rsaVerify(RsaVerifyParam param) {
        String key = param.getKey();
        String data = param.getData();
        String sign = param.getSign();
        PublicKey publicKey;
        try {
            publicKey = RsaUtil.publicKey(key);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_PUBLIC_KEY_ERROR, e);
        }
        boolean verify;
        try {
            verify = RsaUtil.verify(publicKey, data, sign);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_VERIFY_ERROR, e);
        }
        RsaVerifyData d = new RsaVerifyData();
        d.setVerify(verify);
        return d;
    }

    public RsaKeyData rsaGenerateKey(RsaKeyParam param) {
        Integer keySize = param.getKeySize();
        KeyPair keyPair;
        try {
            keyPair = RsaUtil.keyPair(keySize);
        } catch (NoSuchAlgorithmException e) {
            throw new AppException(SecurityError.RSA_GENERATE_KEY_PAIR_ERROR, e);
        }
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        String rsaPrivateKey;
        String rsaPublicKey;
        try {
            rsaPrivateKey = RsaUtil.privateKey(privateKey);
            rsaPublicKey = RsaUtil.publicKey(publicKey);
        } catch (IOException e) {
            throw new AppException(SecurityError.RSA_GENERATE_KEY_PAIR_ERROR, e);
        }
        RsaKeyData data = new RsaKeyData();
        data.setPrivateKey(rsaPrivateKey);
        data.setPublicKey(rsaPublicKey);
        return data;
    }

    public RsaKeyData rsaExtractPublicKey(RsaPrivateKeyParam param) {
        String privateKey = param.getPrivateKey();
        PrivateKey key;
        try {
            key = RsaUtil.privateKey(privateKey);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_PRIVATE_KEY_ERROR, e);
        }
        PublicKey publicKey;
        try {
            publicKey = RsaUtil.publicKey(key);
        } catch (Exception e) {
            throw new AppException(SecurityError.RSA_EXTRACT_PUBLIC_KEY_ERROR, e);
        }
        String rsaPublicKey;
        try {
            rsaPublicKey = RsaUtil.publicKey(publicKey);
        } catch (IOException e) {
            throw new AppException(SecurityError.RSA_EXTRACT_PUBLIC_KEY_ERROR, e);
        }
        RsaKeyData data = new RsaKeyData();
        data.setPublicKey(rsaPublicKey);
        return data;
    }

}
